# -*- coding:utf-8 -*-

# 从客户端向服务器端发送请求消息，比起客户端socket接收服务器端返回的响应消息要简单
# 因为客户端发送请求消息是主动的，在请求报文编辑好之后直接通过socket发送就好

# 本demo是基于socket，手动编写http请求报文，并接收http响应报文的简单类似httplib的demo，
# 目前还不具备识别HTTP/1.1响应状态码，并做相应处理的操作，这方面httplib更全面。
# httplib也是基于socket，但是他是理解http报文含义的。
# 本demo，能实现正确发送、接收报文，但不理解报文内容，比如200报文与404报文对本demo来说无差别

import socket
import re

import mysql.connector as mysqldb

import urlcodec4uni

def select_data(html):
	fp = open('data.txt', 'w')
	conn = mysqldb.connect(host='127.0.0.1', port=3306, user='root', passwd='mysqlpass', db='test', charset='utf8')
	try:
		csr = conn.cursor()
		patt = r'<input type="hidden" name="DataHF" id="DataHF" value="((.|%s)*)" />' % ('\n')
		search_object = re.search(patt, html)
		if search_object:
			data = search_object.group(1)
			data = data.replace('&quot;','\'')
			fp.write(data)
			data = eval(data.replace('true','True').replace('false', 'False').replace('null','None'))
			for group in data:
				rooms = group['rooms']
				for rm in rooms:
					rm_kvs = json_split2sql(rm)
					rm_fields = rm_kvs[0]
					rm_values = rm_kvs[1]
					sql = 'insert into t_p_rooms_yymmdd (%s) values (%s);\n' % (rm_fields, rm_values)
					csr.execute(sql)
					fp.write(sql)
			conn.commit()
	finally:
		fp.close()
		csr.close()
		conn.close()

def fetch_entity(fp, entity_length):
	body = ''
	body_length = 0
	while True:
		msg_line = fp.readline()
		body += msg_line
		body_length += len(msg_line)
		if entity_length - body_length < 100:
			break

	while True:
		msg_line = fp.read(1)
		body += msg_line
		body_length += len(msg_line)
		if body_length == entity_length:
			break

	return body

def page_get(domain, request_message):
	tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	try:
		tcp_socket.connect((domain, 80))
		tcp_socket.sendall(request_message)

		try:
			fp = tcp_socket.makefile('rb')
			#  先要判断是否是分块传输编码
			headers = ''
			try:
				fph = open('response_header.txt', 'w')
				while True:
					msg_line = fp.readline()
					if not msg_line.strip():
						break
					headers += msg_line
				fph.write(headers)
			finally:
				fph.close()

			content_length = None
			patt = r'Content-Length: (\d+)(%s|%s)' % ('\n', '\r\n')
			search_object = re.search(patt, headers)
			if search_object:
				content_length = int(search_object.group(1).strip())

			transfer_encoding = None
			patt = r'Transfer-Encoding: (chunked)'
			search_object = re.search(patt, headers)
			if search_object:
				transfer_encoding = search_object.group(1).strip()

			if transfer_encoding:
				body = ''
				chunk_length = 0
				while True:
					chunk_length = int(fp.readline().strip(), 16)
					# print (chunk_length, 1)
					if chunk_length == 0:
						break
					body += fetch_entity(fp, chunk_length)
					fp.readline() # 分块传输会在块结尾添加一个行结尾符，最后一块没有
			else:
				body = fetch_entity(fp, content_length)


			fpb = open('response_body.html', 'w')
			try:
				fpb.write(body)
			finally:
				fpb.close()
		finally:
			fp.close()
	finally:
		tcp_socket.close()

	return (headers, body)

def genarate_request_message(method, uri, params, headers, body=None):
	params_str = ''
	params = browser_jsonlike_format2dict(params)
	for pm in params:
		params_str += '%s=%s&' % (pm, urlcodec4uni.quote_uni(params[pm], 'utf-8', 'unicode'))
	params_str = params_str[None:-1]

	headers_str = ''
	headers = browser_jsonlike_format2dict(headers)
	for hd in headers:
		headers_str += '%s: %s\n' % (hd, headers[hd])
	
	headers_str = headers_str[None:-1]

	return '%s %s?%s %s\n%s\n\n' % (method, uri, params_str, 'HTTP/1.1', headers_str)

# 复制浏览器请求头信息，将此请求头信息转化为一个字典格式
def browser_jsonlike_format2dict(headers_file_name):
	header_dict = {}
	try:
		fp = open(headers_file_name, 'r')
		for header_line in fp:
			header_line =  header_line.strip()
			inx = header_line.find(':')
			header_name = header_line[0:inx]
			header_value = header_line[inx+1:None]
			header_dict[header_name] = header_value
	finally:
		fp.close()
	return header_dict

# 将json格式文本转换为sql的字段名字段值
def json_split2sql(json):
	keys_str = ''
	values_str = ''
	typestr = type('foo')
	for key in json.keys():
		keys_str += "`%s`, " % (key)

		value = json[key]
		if type(value) is typestr:
			value = "'%s', " % (value)
		elif value is None:
			value = 'null, '
		else:
			value = '%s, '% (value)
		values_str += value

	return keys_str[:-2], values_str[:-2]


def test():
	request_message =  genarate_request_message('GET', '/315web/HtmlPage/ShowRoomsNew.aspx', 'params.txt', 'headers.txt')
	request_message = '''POST http://housing.gzcc.gov.cn/search/project/sellForm_pic.jsp?chnlname=fdcxmxx HTTP/1.1
Host: housing.gzcc.gov.cn
Connection: keep-alive
Content-Length: 84
Cache-Control: max-age=0
Origin: http://housing.gzcc.gov.cn
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://housing.gzcc.gov.cn/search/project/sellForm.jsp?pjID=47140&presell=20090173&chnlname=fdcxmxx
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: JSESSIONID=3EFEA92F4568823046FE2A921A244866

modeID=1&hfID=0&unitType=0&houseStatusID=0&totalAreaID=0&inAreaID=0&buildingID=14550'''
	response = page_get('housing.gzcc.gov.cn', request_message)
	# select_data(response[1])

if __name__ == "__main__":
	test()